#!/usr/bin/env python
# encoding: utf-8

"""
@file: fenduanbudengshi.py
@time: 2016/11/21 上午9:57
"""
# 分段不等式问题
from mathsolver.functions.root.jiefangchenzu import *
from mathsolver.functions.budengshi import common_opers as co
from sympy import S
import re
from mathsolver.functions.budengshi.ineqs_funcs import FragmentIneqs, FenDuanBuDengShi as FenDuanBuDengShi003


# 若函数f(x)=\\left\\{\\begin{array}{c}\\frac{1}{x}x<0\\\\(\\frac{1}{3})^{x}x≥0\\end{array}\\right.则不等式|f(x)|≥\\frac{1}{3}的解集为()

def find_fx(expr):
    """
    提取表达式中的f(x)
    :param expr:
    :return:
    """
    p = r'f\(.*\)'
    m = re.search(p, str(expr))
    tmp_fx = m.group()
    fx = None
    while tmp_fx:
        try:
            tmp_fx = sympify(tmp_fx)
            if str(type(tmp_fx)) == 'f':
                fx = tmp_fx
                break
            else:
                tmp_fx = str(tmp_fx)[:len(str(tmp_fx)) - 1]
        except Exception:
            tmp_fx = str(tmp_fx)[:len(str(tmp_fx)) - 1]
    return fx


# 如果是作为元函数进行调用
# input: 形如((表达式1, 变量取值范围1),(表达式2, 变量取值范围2)); "f(x)>x的多项式"
# output 取值范围
class FenDuanBuDengShi001(BaseFunction):
    def solver(self, *args):
        self.label.add('分段不等式')
        arg0 = args[0]
        if isinstance(args[1], str):
            expr_s = args[1]
            p = '>=|>|<=|<'
            m = re.search(p, expr_s)
            ineq_op = m.group()
            ineq_info = expr_s.split(ineq_op)
            ineq_info.insert(1, ineq_op)
            target_ineq = BaseIneq(ineq_info)
        elif isinstance(args[1], BaseExpression):
            expr_s = args[1].value
            p = '>=|>|<=|<'
            m = re.search(p, expr_s)
            ineq_op = m.group()
            ineq_info = expr_s.split(ineq_op)
            ineq_info.insert(1, ineq_op)
            target_ineq = BaseIneq(ineq_info)
        else:
            target_ineq = args[1]
        target_ineq_left, target_ineq_op, target_ineq_right = target_ineq.sympify()
        target_ineq_f = target_ineq_left - target_ineq_right
        target_ineq_f_str = str(target_ineq_f)
        fx = find_fx(target_ineq_f_str)
        target_ineq_str = ''.join(target_ineq.value)
        # fx = find_fx(target_ineq_str)
        variable = list(sympify(fx).free_symbols)[0]
        # segfs ((表达式1, 变量取值范围1),(表达式2, 变量取值范围2))
        segfs = map(lambda e: (sympify(e['main']), BaseIneq(e['inequality'][0])), arg0.value['expression'])
        # result_intl = S.Reals
        result_intls = []
        for f, intl_ineq in segfs:
            tmp_intl = solveset(''.join(intl_ineq.value), domain=S.Reals)
            comp_f = co.comp_func(f, fx)
            tmp_ineq = target_ineq_str.replace(str(fx), str(comp_f))
            self.steps.append(['当 %s 时，' % intl_ineq.printing(),
                               target_ineq.printing() + '即 %s' % tmp_ineq])
            tmp_intl = tmp_intl.intersect(solveset(tmp_ineq, domain=S.Reals))
            # result_intl = result_intl.union(tmp_intl)
            result_intls.append(tmp_intl)
        result_intl = co.intervals_union(result_intls)
        self.steps.append(['综上，不等式%s的解集为%s' % (target_ineq.printing(), new_latex(result_intl)), ''])
        # self.output.append(co.to_base_interval(result_intl))
        self.output.append(BaseSymbolValue({variable: result_intl}))
        return self


# paramer1: 分段函数 paramer2: 目标不等式表达式
class FenDuanBuDengShi002(BaseFunction):
    def solver(self, *args):
        raise Exception('try error')
        arg0 = args[0]
        arg1 = args[1]
        # ------------------前置处理-------------------
        f_segs = arg0
        l_expr, op, r_expr = arg1.sympify()
        ineq_f = l_expr - r_expr
        param_symb = list(ineq_f.free_symbols)

        return self


# 分段不等式的元函数
class FenDuanBuDengShi(BaseFunction):
    CLS = [FenDuanBuDengShi001, FragmentIneqs, FenDuanBuDengShi002, FenDuanBuDengShi003]

    def solver(self, *args):
        r = None
        for cl in FenDuanBuDengShi.CLS:
            try:
                r = cl(verbose=True).solver(*args)
                break
            except Exception:
                pass
        if not r:
            raise 'try fail'
        return r
